package com.markhsiu.common.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * 任务工厂
 */
public class TaskFactory {

	private static final Logger logger = LoggerFactory.getLogger(TaskFactory.class);

	private String workerName = "workerTaskPool";
	private String timeoutName = "timeoutTaskPool";
	private ThreadPoolTaskExecutor workerExecutor = new ThreadPoolTaskExecutor();
	private ThreadPoolTaskExecutor timeoutExecutor = new ThreadPoolTaskExecutor();

	private static final TaskFactory POOLS = new TaskFactory();
	public static final int TIMEOUT = 5 * 60;

	private TaskFactory() {
		setWorker().setTimeouter();
	}
	
	private TaskFactory setWorker() {
		RejectedExecutionHandler handler = new AbortPolicyWithReport(workerName);
		ThreadFactory threadFactory = new ThreadFactoryBuilder().setName(workerName).build();
		workerExecutor.initializeExecutor(threadFactory, handler);
		return this;

	}

	private TaskFactory setTimeouter() {
		RejectedExecutionHandler handler = new AbortPolicyWithReport(timeoutName);
		ThreadFactory threadFactory = new ThreadFactoryBuilder().setName(timeoutName).build();
		timeoutExecutor.initializeExecutor(threadFactory, handler);
		return this;
	}

	public static <T> T executeBack(Callable<T> caller, String msg) throws InterruptedException, ExecutionException {
		return executeBack(caller, TIMEOUT, TimeUnit.SECONDS, msg);
	}
	
	public static <T> void execute(Callable<T> caller, String msg) {
		execute(caller, TIMEOUT, TimeUnit.SECONDS, msg);
	}
	
	
	public static <T> T executeBack(final Callable<T> caller, final long timeout, final TimeUnit unit, final String msg) throws InterruptedException, ExecutionException {
		return POOLS.timeoutExecutor.submit(new Callable<T>() {

			@Override
			public T call() {

				T t = null;
				Future<T> future = POOLS.workerExecutor.submit(caller);
				try {
					t = future.get(timeout, unit);
					
					logger.info(" msg :{} success:{} ",msg,t);
				} catch (Exception e) {
					logger.error("cancl :{}",msg);
					future.cancel(true);
					return null;
				}
				return t;
			}

		}).get();
	}


	public static <T> void execute(final Callable<T> caller,final long timeout, final TimeUnit unit, final String msg) {
		
		POOLS.timeoutExecutor.submit(new Runnable() {

			@Override
			public void run() { 
				Future<T> future = POOLS.workerExecutor.submit(caller);
				try {

					T t = future.get(timeout, unit);
					logger.info(" msg :{} success:{} ",msg,t);
				} catch (Exception e) {
					logger.error("cancl :{}",msg);
					logger.error("error :{}",e);
					future.cancel(true);
				}
			}

		});
	}
}
